package backend;

import logs.LogFactory;

import org.apache.log4j.Logger;

import backend.db.ORM;

public class InputValidation {
  private static final Logger logger = LogFactory.getLog(InputValidation.class);
  public static final char POINT = '.';
  public static final char SPACE = ' ';
  
  private static boolean validDate(final String date) {
    if (date.length() != 10 || date.charAt(2) != POINT || date.charAt(5) != POINT
        || !validNumbers(date.substring(0, 2)) || !validNumbers(date.substring(3, 5))
        || !validNumbers(date.substring(6)))
      return false;
    if (date.charAt(0) > '3' || date.charAt(0) == '3' && date.charAt(1) > '1' || date.charAt(0) == '0'
        && date.charAt(1) == '0')
      return false;
    if (date.charAt(3) > '1' || date.charAt(3) == '1' && date.charAt(4) > '2' || date.charAt(3) == '0'
        && date.charAt(4) == '0')
      return false;
    if (date.charAt(3) == '0' && date.charAt(4) == '2' && date.charAt(0) == '3')
      return false;
    return true;
  }
  
  public static boolean dateBefore(final String dateBefore, final String dateAfter) {
    if (!validDate(dateBefore) || !validDate(dateAfter))
      return false;
    final int daysA = Integer.parseInt(dateBefore.substring(0, 2));
    final int daysB = Integer.parseInt(dateAfter.substring(0, 2));
    final int monthsA = Integer.parseInt(dateBefore.substring(3, 5));
    final int monthsB = Integer.parseInt(dateAfter.substring(3, 5));
    final int yearsA = Integer.parseInt(dateBefore.substring(6));
    final int yearsB = Integer.parseInt(dateAfter.substring(6));
    if (yearsA != yearsB)
      return yearsB > yearsA;
    if (monthsA != monthsB)
      return monthsB > monthsA;
    return daysB > daysA;
  }
  
  public static boolean validName(final String name) {
    for (int i = 0; i < name.length(); i++) {
      final char c = name.charAt(i);
      if (c != SPACE && !validLetter(c))
        return false;
    }
    return true;
  }
  
  public static boolean validCourseName(final String cName) {
    for (int i = 0; i < cName.length(); i++) {
      final char c = cName.charAt(i);
      if (!validNumber(c) && !validLetter(c) && c != SPACE)
        return false;
    }
    return true;
  }
  
  private static boolean validUserName(final String username) {
    for (int i = 0; i < username.length(); i++) {
      final char c = username.charAt(i);
      if (!validNumber(c) && !validLetter(c))
        return false;
    }
    return true;
  }
  
  private static boolean validNumber(final char c) {
    if (c >= '0' && c <= '9')
      return true;
    return false;
  }
  
  public static boolean validCreditPoints(final String c) {
    if (!validNumbers(c)) {
      if (c.charAt(1) == POINT && validNumber(c.charAt(0)) && validNumbers(c.substring(2)))
        return true;
      return false;
    }
    return true;
  }
  
  public static boolean validNumbers(final String num) {
    for (int i = 0; i < num.length(); i++) {
      final char c = num.charAt(i);
      if (!validNumber(c))
        return false;
    }
    return true;
  }
  
  private static boolean validLetter(final char c) {
    if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')
      return true;
    return false;
  }
  
  public static boolean validLetters(final String str) {
    for (int i = 0; i < str.length(); i++) {
      final char c = str.charAt(i);
      if (!validLetter(c))
        return false;
    }
    return true;
  }
  
  private static boolean validPassword(final String pass) {
    final int pLength = pass.length();
    if (pLength > 32)
      return false;
    for (int i = 0; i < pLength; i++) {
      final char c = pass.charAt(i);
      if (!validLetter(c) && !validNumber(c))
        return false;
    }
    return true;
  }
  
  public static boolean passwordsMatch(final String pass, final String confirm) {
    return validPassword(pass) && validPassword(confirm) && pass.equals(confirm);
  }
  
  public static boolean admin(final String username) {
    final User user = ORM.getUser(username);
    return user != null && user.isAdmin();
  }
  
  private static boolean student(final String username) {
    final User user = ORM.getUser(username);
    return user != null && user.isStudent();
  }
  
  private static boolean legalRole(final String role) {
    return "student".equals(role) || "administrator".equals(role);
  }
  
  private static boolean adminVerified(final String role, final String adminVeri) {
    return !"administrator".equals(role) || Util.administratorVerification.equals(adminVeri);
  }
  
  private static boolean userExists(final String username) {
    return null != ORM.getUser(username);
  }
  
  private static boolean requiredFields(final String... strings) {
    for (final String s : strings)
      if (s == null || s.isEmpty())
        return false;
    return true;
  }
  
  private static boolean requiredFields(final String username, final String password, final String role,
      final String name) {
    return requiredFields(username, name) || "administrator".equals(role) && !password.isEmpty();
  }
  
  private static boolean validSessionType(final String type) {
    return type.equals("tutorial") || type.equals("lecture");
  }
  
  private static boolean validTime(final String start, final String duration) {
    if (!validNumbers(start) || !validNumbers(duration))
      return false;
    final int sTime = Integer.parseInt(start);
    final int dTime = Integer.parseInt(duration);
    if (sTime >= 8 && sTime <= 12 && dTime >= 1 && dTime <= 4)
      return true;
    if (sTime == 17 && dTime >= 2)
      return false;
    if (sTime == 16 && dTime >= 3)
      return false;
    if (sTime == 15 && dTime == 4)
      return false;
    return true;
  }
  
  private static boolean validDay(final String day) {
    if (!day.equals("Sunday") && !day.equals("Monday") && !day.equals("Tuesday") && !day.equals("Wednesday")
        && !day.equals("Thursday") && !day.equals("Friday") && !day.equals("Saturday"))
      return false;
    return true;
  }
  
  private static boolean validValue(final String action, final String value) {
    if (action.equals("password"))
      return validPassword(value);
    if (action.equals("name"))
      return validName(value);
    if (action.equals("phone"))
      return validNumbers(value);
    if (action.equals("address"))
      return true;
    return false;
  }
  
  public static boolean validateRegistration(final String username, final String password,
      final String confirm, final String name, final String role, final String adminVeri,
      final String address, final String phone) {
    logger.debug("validateRegistration");
    return Util.noNulls(username, password, confirm, name, role, adminVeri, address, phone)
        && requiredFields(username, password, role, name) && passwordsMatch(password, confirm)
        && legalRole(role) && adminVerified(role, adminVeri) && validName(name) && validNumbers(phone)
        && validUserName(username) && !userExists(username);
  }
  
  public static boolean validateCourse(final String username, final String courseId, final String courseName,
      final String lecturerInCharge, final String moedA, final String moedB, final String description,
      final String creditPoints, final String capacity, final String groupNum) {
    logger.debug("validateCourse");
    // removed because these make extra DB queries:
    // if (!requiredFields(username, courseId, courseName, lecturerInCharge,
    // moedA, moedB, description,
    // creditPoints, capacity, groupNum))
    // logger.debug("1");
    // if (!admin(username))
    // logger.debug("2");
    // if (!validNumbers(courseId))
    // logger.debug("3");
    // if (!validCourseName(courseName))
    // logger.debug("4");
    // if (!validName(lecturerInCharge))
    // logger.debug("5");
    // if (!dateBefore(moedA, moedB))
    // logger.debug("6");
    // if (!validCreditPoints(creditPoints))
    // logger.debug("7");
    // if (!validNumbers(capacity))
    // logger.debug("8");
    // if (!validNumbers(groupNum))
    // logger.debug("9");
    return requiredFields(username, courseId, courseName, lecturerInCharge, moedA, moedB, description,
        creditPoints, capacity, groupNum)
        && admin(username)
        && validNumbers(courseId)
        && validCourseName(courseName)
        && validName(lecturerInCharge)
        && dateBefore(moedA, moedB)
        && validCreditPoints(creditPoints) && validNumbers(capacity) && validNumbers(groupNum);
  }
  
  public static boolean validateSession(final String courseId, final String day, final String start,
      final String duration, final String teacher, final String classLocation, final String type) {
    return Util.noNulls(courseId, day, start, duration, teacher, classLocation, type) && validDay(day)
        && validTime(start, duration) && validName(teacher) && validSessionType(type);
  }
  
  public static boolean validateEditUserAccount(final String username, final String action, final String value) {
    if (!student(username) && !admin(username))
      return false;
    return validValue(action, value);
  }
}